package k8s

import (
	"bytes"
	"context"
	"fmt"
	"time"

	k8serrs "k8s.io/apimachinery/pkg/api/errors"

	"gitee.com/hexug/go-tools/common/validate"
	"gitee.com/hexug/go-tools/logger"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/json"
	"k8s.io/client-go/kubernetes/scheme"
	"k8s.io/client-go/tools/remotecommand"
)

func (g *implK8s) CreatePod(c context.Context, req *CreatePodRequest) (*corev1.Pod, error) {
	start := time.Now()
	defer func() {
		logger.L().Infof("elapsed K8SAPI_CreatePod:%v", time.Since(start))
	}()
	if err := validate.V().Struct(req); err != nil {
		logger.L().Errorf("参数校验失败:%v", err)
		return nil, fmt.Errorf("参数校验失败:%v", err)
	}

	// 1. 参数校验
	if g.Clientset == nil {
		logger.L().Errorf("clientset不能为nil")
		return nil, fmt.Errorf("clientset不能为nil")
	}

	// 2. 解析YAML字符串为Pod对象
	pod, err := parseYAMLToPod(req.PodYaml)
	if err != nil {
		logger.L().Errorf("解析YAML失败: %v", err)
		return nil, fmt.Errorf("解析YAML失败: %w", err)
	}

	// 3. 获取Pod对象
	reqGetPod := NewGetPodRequest(pod.Name)
	pd, err := g.GetPod(c, reqGetPod)
	if err == nil {
		logger.L().Infof("POD %s 已存在，不可重复创建", pod.Name)
		return pd, fmt.Errorf("POD %s 已存在，不可重复创建", pod.Name)
	}

	if g.Namespace != "" {
		pod.Namespace = g.Namespace
	} else {
		// 3. 补充默认值（如果YAML中未指定）
		if pod.Namespace == "" {
			pod.Namespace = corev1.NamespaceDefault
		} else {
			pod.Namespace = g.Namespace
		}
	}

	// 4. 设置上下文超时
	ctx, cancel := context.WithTimeout(c, 60*time.Second)
	defer cancel()

	// 5. 尝试创建Deployment
	pod, err = g.CoreV1().Pods(pod.Namespace).Create(
		ctx,
		pod,
		metav1.CreateOptions{},
	)
	if err != nil {
		// 处理常见错误类型
		return handleCreatePodError(c, pod, err)
	}
	return pod, nil
}

func (g *implK8s) GetPod(c context.Context, req *GetPodRequest) (*corev1.Pod, error) {
	start := time.Now()
	defer func() {
		logger.L().Infof("K8SAPI_GetPod:%v", time.Since(start))
	}()
	if err := validate.V().Struct(req); err != nil {
		logger.L().Errorf("参数校验失败:%v", err)
		return nil, fmt.Errorf("参数校验失败:%v", err)
	}
	pod, err := g.CoreV1().Pods(g.Namespace).Get(c, req.Name, metav1.GetOptions{})
	if err != nil {
		logger.L().Errorf("Failed to get pod: %v", err)
		return nil, fmt.Errorf("failed to get pod: %v", err)
	}
	return pod, nil
}

func (g *implK8s) ListPod(c context.Context, req *ListPodRequest) (*corev1.PodList, error) {
	start := time.Now()
	defer func() {
		logger.L().Infof("K8SAPI_ListPod:%v", time.Since(start))
	}()
	if err := validate.V().Struct(req); err != nil {
		logger.L().Errorf("参数校验失败:%v", err)
		return nil, fmt.Errorf("参数校验失败:%v", err)
	}

	labelSelector := metav1.LabelSelector{MatchLabels: req.LabelMap}
	listOp := metav1.ListOptions{
		LabelSelector: labels.Set(labelSelector.MatchLabels).String(),
	}
	return g.CoreV1().Pods(g.Namespace).List(c, listOp)
}

func (g *implK8s) ExecInPod(c context.Context, req *ExecInPodRequest) ([]byte, []byte, error) {
	start := time.Now()
	defer func() {
		logger.L().Infof("%s elapsed K8SAPI_ExecInPod:%v", req.PodName, time.Since(start))
	}()
	if err := validate.V().Struct(req); err != nil {
		logger.L().Errorf("参数校验失败:%v", err)
		return nil, nil, fmt.Errorf("参数校验失败:%v", err)
	}
	reqi := g.CoreV1().RESTClient().Post().Resource("pods").Name(req.PodName).Namespace(g.Namespace).SubResource("exec")
	cmd := []string{"sh", "-c", req.Cmd}
	option := &corev1.PodExecOptions{
		TypeMeta:  metav1.TypeMeta{},
		Stdin:     false,
		Stdout:    true,
		Stderr:    true,
		TTY:       false,
		Container: req.ContainerName,
		Command:   cmd,
	}
	reqi.VersionedParams(option, scheme.ParameterCodec)
	// 建立多路复用双向流链接
	exec, err := remotecommand.NewSPDYExecutor(g.Config, "POST", reqi.URL())
	if err != nil {
		return nil, nil, err
	}
	var stdout, stderr bytes.Buffer
	err = exec.Stream(remotecommand.StreamOptions{
		Stdin:             nil,
		Stdout:            &stdout,
		Stderr:            &stderr,
		Tty:               false,
		TerminalSizeQueue: nil,
	})
	if err != nil {
		return nil, nil, err
	}
	return stdout.Bytes(), stderr.Bytes(), nil
}

func (g *implK8s) PatchPodFromJson(c context.Context, req *PatchPodFromJsonRequest) (*corev1.Pod, error) {
	start := time.Now()
	defer func() {
		logger.L().Infof("%s elapsed K8SAPI_PatchPod:%v", req.Pod, time.Since(start))
	}()
	if err := validate.V().Struct(req); err != nil {
		logger.L().Errorf("参数校验失败:%v", err)
		return nil, fmt.Errorf("参数校验失败:%v", err)
	}
	bytesData, err := json.Marshal(req.Data)
	if err != nil {
		return nil, err
	}
	return g.CoreV1().Pods(g.Namespace).Patch(c, req.Pod, types.JSONPatchType, bytesData, metav1.PatchOptions{})
}

func (g *implK8s) PutPodFromYaml(c context.Context, req *PutPodFromYamlRequest) (*corev1.Pod, error) {
	start := time.Now()
	defer func() {
		logger.L().Infof("elapsed K8SAPI_PutPodFromYaml:%v", time.Since(start))
	}()
	if err := validate.V().Struct(req); err != nil {
		logger.L().Errorf("参数校验失败:%v", err)
		return nil, fmt.Errorf("参数校验失败:%v", err)
	}

	// 1. 参数校验
	if g.Clientset == nil {
		logger.L().Errorf("clientset不能为nil")
		return nil, fmt.Errorf("clientset不能为nil")
	}

	// 2. 解析YAML字符串为Pod对象
	pod, err := parseYAMLToPod(req.YamlStr)
	if err != nil {
		logger.L().Errorf("解析YAML失败: %v", err)
		return nil, fmt.Errorf("解析YAML失败: %w", err)
	}

	// 3. 设置命名空间
	if g.Namespace != "" {
		pod.Namespace = g.Namespace
	} else if pod.Namespace == "" {
		pod.Namespace = corev1.NamespaceDefault
	}

	// 4. 检查Pod是否存在
	existingPod, err := g.CoreV1().Pods(pod.Namespace).Get(c, pod.Name, metav1.GetOptions{})

	// 设置上下文超时
	ctx, cancel := context.WithTimeout(c, 60*time.Second)
	defer cancel()

	if err != nil {
		// 如果Pod不存在，则创建
		if k8serrs.IsNotFound(err) {
			return g.CoreV1().Pods(pod.Namespace).Create(ctx, pod, metav1.CreateOptions{})
		}
		// 其他错误
		logger.L().Errorf("获取Pod失败: %v", err)
		return nil, fmt.Errorf("获取Pod失败: %w", err)
	}

	// 如果Pod存在，只更新允许修改的字段
	// 1. 保留原有元数据
	pod.ObjectMeta = existingPod.ObjectMeta

	// 2. 只复制允许更新的字段
	// 允许更新的字段：容器镜像、资源限制、activeDeadlineSeconds、tolerations等
	existingPod.Spec.ActiveDeadlineSeconds = pod.Spec.ActiveDeadlineSeconds
	existingPod.Spec.Tolerations = append(existingPod.Spec.Tolerations, pod.Spec.Tolerations...)

	// 更新容器信息（只更新允许修改的字段）
	for _, container := range pod.Spec.Containers {
		for j, existingContainer := range existingPod.Spec.Containers {
			if container.Name == existingContainer.Name {
				// 更新镜像
				existingPod.Spec.Containers[j].Image = container.Image
				// 更新资源限制
				existingPod.Spec.Containers[j].Resources = container.Resources
				break
			}
		}
	}

	// 更新初始化容器
	for _, initContainer := range pod.Spec.InitContainers {
		for _, existingInitContainer := range existingPod.Spec.InitContainers {
			if initContainer.Name == existingInitContainer.Name {
				existingInitContainer.Image = initContainer.Image
				existingInitContainer.Resources = initContainer.Resources
				break
			}
		}
	}

	// 执行更新操作
	return g.CoreV1().Pods(pod.Namespace).Update(ctx, existingPod, metav1.UpdateOptions{})
}

func (g *implK8s) DeletePod(c context.Context, req *DeletePodRequest) (*corev1.Pod, error) {
	start := time.Now()
	defer func() {
		logger.L().Infof("%s elapsed K8SAPI_DeletePod:%v", req.Name, time.Since(start))
	}()
	if err := validate.V().Struct(req); err != nil {
		logger.L().Errorf("参数校验失败:%v", err)
		return nil, fmt.Errorf("参数校验失败:%v", err)
	}
	reqGetPod := NewGetPodRequest(req.Name)
	pod, err := g.GetPod(c, reqGetPod)
	if err != nil {
		if k8serrs.IsNotFound(err) || k8serrs.IsGone(err) {
			logger.L().Infof("Pod %s is not found", req.Name)
			return nil, fmt.Errorf("Pod %s is not found", req.Name)
		}
		return nil, err
	}
	deletePolicy := metav1.DeletePropagationBackground
	deleteOptions := metav1.DeleteOptions{
		PropagationPolicy: &deletePolicy,
	}
	err = g.CoreV1().Pods(g.Namespace).Delete(c, req.Name, deleteOptions)
	if err != nil {
		if k8serrs.IsNotFound(err) || k8serrs.IsGone(err) {
			logger.L().Infof("Pod %s is not found", req.Name)
			return nil, fmt.Errorf("Pod %s is not found", req.Name)
		}
		return nil, err
	}
	return pod, nil
}

func (g *implK8s) GetPodStatus(ctx context.Context, req *GetPodStatusRequest) (*GetPodStatusResponse, error) {
	if req == nil {
		return nil, fmt.Errorf("nil request")
	}
	if g.Namespace == "" {
		return nil, fmt.Errorf("namespace not specified")
	}
	if req.PodName == "" {
		return nil, fmt.Errorf("pod name required")
	}

	pod, err := g.Clientset.CoreV1().Pods(g.Namespace).Get(ctx, req.PodName, metav1.GetOptions{})
	if err != nil {
		return nil, err
	}

	resp := NewGetPodStatusResponse()
	resp.HostIP = pod.Status.HostIP
	resp.PodIP = pod.Status.PodIP
	resp.Phase = pod.Status.Phase

	for _, cs := range pod.Status.ContainerStatuses {
		state := cs.State
		last := cs.LastTerminationState

		resp.AddContainerStatus(
			cs.Name,
			cs.Ready,
			cs.RestartCount,
			cs.Image,
			cs.Started,
			&state,
			&last,
		)
	}

	return resp, nil
}
